
#include <stl/set.h>
#include <stl/vector.h>
#include <standard/geometrymath.h>
#include <standard/notification.h>
#include "operator/terrainblockcoloroperator.h"
#include "helper/terrainactiveblockhelperobject.h"
#include "editorscenemgr.h"
#include "scene/editorscene.h"
#include "terrain/terrainblock.h"
#include "terrain/terrainobject.h"
#include "ui/terrainpanel.h"
#include "command/commandmgr.h"
#include "global.h"





CTerrainColorOperator::CTerrainColorOperator( CEditorSceneMgr* pSceneMgr ):
COperator( pSceneMgr ) {
    m_eOperatorType = EOT_TERRAIN_COLOR_EDIT;
    m_bIsButtonDown = False;
    m_nButtonDownX = 0;
    m_nButtonDownY = 0;

    m_nButtonWorkX = 0;
    m_nButtonWorkY = 0;
}
CTerrainColorOperator::~CTerrainColorOperator(){

}
bool32 CTerrainColorOperator::Init(){
    int32 _nBrushType = CTerrainPanel::GetInterface()->GetSelectTerrainBrushType();
    int32 _nBrushSize = CTerrainPanel::GetInterface()->GetSelectTerrainBrushSize();
    m_rTerrainActiveBlockHelperObject = NEW CTerrainActiveBlockHelperObject();
    m_rTerrainActiveBlockHelperObject->Init( m_pSceneMgr->GetTerrainObject(), _nBrushType, _nBrushSize);
    m_pSceneMgr->GetScene()->AddChild(m_rTerrainActiveBlockHelperObject.GetEntityData());
    m_pSceneMgr->SetSceneVisibleMode( 0 );
    NOTIFICATION_REGISTER(SETTERRAINBRUSHTYPENOTIFICATION, 0, this, CTerrainColorOperator::OnNotification_SetTerrainBrushType);
    return True;
}
bool32 CTerrainColorOperator::Final(){
    m_pSceneMgr->GetScene()->RemoveChild(m_rTerrainActiveBlockHelperObject.GetEntityData());
    m_rTerrainActiveBlockHelperObject.Detach();
    NOTIFICATION_REMOVE_DELEGATE(SETTERRAINBRUSHTYPENOTIFICATION, this, CTerrainColorOperator::OnNotification_SetTerrainBrushType);
    return True;
}
bool32 CTerrainColorOperator::OnLMouseDown( int32 x, int32 y ){
    STerrainSelectedPosInfo _sTerrainSelectedPosInfo;
    CTerrainBlock* _pTerrainBlock = m_pSceneMgr->GetSelectBlock(x, y, &_sTerrainSelectedPosInfo );
    if (_pTerrainBlock) {
        SSETSTATUSCOORDTEXT _sSETSTATUSCOORDTEXT;
        _sSETSTATUSCOORDTEXT.m_fPosX = _sTerrainSelectedPosInfo.m_vPos[0];
        _sSETSTATUSCOORDTEXT.m_fPosY = _sTerrainSelectedPosInfo.m_vPos[1];
        _sSETSTATUSCOORDTEXT.m_fPosZ = _sTerrainSelectedPosInfo.m_vPos[2];
        _sSETSTATUSCOORDTEXT.m_nCellX = _sTerrainSelectedPosInfo.m_nCellX;
        _sSETSTATUSCOORDTEXT.m_nCellY = _sTerrainSelectedPosInfo.m_nCellY;

        NOTIFICATION_SEND(SETSTATUSCOORDTEXT, 0, 0, &_sSETSTATUSCOORDTEXT);
        int32 _nBrushSize = CTerrainPanel::GetInterface()->GetSelectTerrainBrushSize();
        list<CTerrainBlock*>* _pvTerrainBlockList = m_rTerrainActiveBlockHelperObject->UpdateActiveBlock( _sTerrainSelectedPosInfo.m_nCellX, _sTerrainSelectedPosInfo.m_nCellY, _nBrushSize);
        m_bIsButtonDown = True;
        m_nButtonWorkX = x;
        m_nButtonWorkY = y;
        m_nButtonDownX = x;
        m_nButtonDownY = y;

        m_vTerrainCellHeightInfoList.clear();
        return True;
    }
    return False;
}
bool32 CTerrainColorOperator::OnMouseMove( int32 x, int32 y ){
    STerrainSelectedPosInfo _sTerrainSelectedPosInfo;
    CTerrainBlock* _pTerrainBlock = m_pSceneMgr->GetSelectBlock(x, y, &_sTerrainSelectedPosInfo );
    if (_pTerrainBlock) {
        SSETSTATUSCOORDTEXT _sSETSTATUSCOORDTEXT;
        _sSETSTATUSCOORDTEXT.m_fPosX = _sTerrainSelectedPosInfo.m_vPos[0];
        _sSETSTATUSCOORDTEXT.m_fPosY = _sTerrainSelectedPosInfo.m_vPos[1];
        _sSETSTATUSCOORDTEXT.m_fPosZ = _sTerrainSelectedPosInfo.m_vPos[2];
        _sSETSTATUSCOORDTEXT.m_nCellX = _sTerrainSelectedPosInfo.m_nCellX;
        _sSETSTATUSCOORDTEXT.m_nCellY = _sTerrainSelectedPosInfo.m_nCellY;
        NOTIFICATION_SEND(SETSTATUSCOORDTEXT, 0, 0, &_sSETSTATUSCOORDTEXT );
        int32 _nBrushSize = CTerrainPanel::GetInterface()->GetSelectTerrainBrushSize();
        list<CTerrainBlock*>* _pvTerrainBlockList = m_rTerrainActiveBlockHelperObject->UpdateActiveBlock( _sTerrainSelectedPosInfo.m_nCellX, _sTerrainSelectedPosInfo.m_nCellY, _nBrushSize);
        if (m_bIsButtonDown) {
            if (m_nButtonWorkX != x || m_nButtonWorkY != y) {
                color32 _nBrushColor = CTerrainPanel::GetInterface()->GetSelectTerrainBrushColor();
                _Work(_sTerrainSelectedPosInfo.m_nCellX, _sTerrainSelectedPosInfo.m_nCellY, _nBrushSize, _nBrushColor);
                m_nButtonWorkX = x;
                m_nButtonWorkY = y;
                return True;
            }
        }
    }
    return False;
}
bool32 CTerrainColorOperator::OnLMouseUp( int32 x, int32 y ){
    bool32 _bResult = False;
    if (m_bIsButtonDown) {
        if (m_nButtonDownX == x || m_nButtonDownY == y) {
            STerrainSelectedPosInfo _sTerrainSelectedPosInfo;
            CTerrainBlock* _pTerrainBlock = m_pSceneMgr->GetSelectBlock(x, y, &_sTerrainSelectedPosInfo);
            if (_pTerrainBlock) {
                int32 _nBrushSize = CTerrainPanel::GetInterface()->GetSelectTerrainBrushSize();
                color32 _nBrushColor = CTerrainPanel::GetInterface()->GetSelectTerrainBrushColor();
                _Work(_sTerrainSelectedPosInfo.m_nCellX, _sTerrainSelectedPosInfo.m_nCellY, _nBrushSize, _nBrushColor);
                _bResult = True;
            }
        }

        _FinishedWork();
    }
    m_bIsButtonDown = False;
    m_nButtonDownX = 0;
    m_nButtonDownY = 0;

    m_nButtonWorkX = 0;
    m_nButtonWorkY = 0;
    return _bResult;
}
void CTerrainColorOperator::OnNotification_SetTerrainBrushType( int32 w, int32 l, void* pUserData ){
    m_rTerrainActiveBlockHelperObject->SetBrushInfo(w, l);
}
void CTerrainColorOperator::_AddTerrainCellColorInfo( int32 x, int32 y, color32 cColor ){
    uint32 _nKey = MAKELONG( y, x );
    if(m_vTerrainCellHeightInfoList.find( _nKey ) == m_vTerrainCellHeightInfoList.end()){
        m_vTerrainCellHeightInfoList.insert( _nKey, cColor );
    }
}
void CTerrainColorOperator::_Work( int32 nCellX, int32 nCellY, int32 nBrushSize, color32 cBrushColor ){
    const float _fRiseHeight = 10.0f;
    int32 _nCoordX = nCellX;
    int32 _nCoordY = nCellY;
    int32 _nHalfBrushSize = nBrushSize / 2;
    set<CTerrainBlock*> _vTerrainBlockList;

    CTerrainBlock* _vTerrainBlock[4];
    CTerrainObject* _pTerrainObject = m_pSceneMgr->GetTerrainObject();
    if (_nHalfBrushSize > 0) {
        float _fMaxDistance = sqrt(Distance(_nCoordX, _nCoordY, _nCoordX + _nHalfBrushSize, _nCoordY + _nHalfBrushSize));
        for (int32 j = _nCoordY - _nHalfBrushSize; j <= _nCoordY + _nHalfBrushSize; j++) {
            for (int32 i = _nCoordX - _nHalfBrushSize; i <= _nCoordX + _nHalfBrushSize; i++) {
                if(i < 0 || j < 0 || i >= _pTerrainObject->m_nCellCountX || j >= _pTerrainObject->m_nCellCountY)
                    continue;
                
                int32 _nTerrainBlock = _pTerrainObject->GetCellBlock( i, j, _vTerrainBlock );
                for( int32 n = 0; n < _nTerrainBlock; n ++ ){
                    _vTerrainBlockList.insert( _vTerrainBlock[n] );
                }
                color32 _nOldColor = _pTerrainObject->GetCellColor( i, j );
                _AddTerrainCellColorInfo( i, j, _nOldColor );
                _pTerrainObject->SetCellColor( i, j, cBrushColor );
            }
        }
    }else {
        int32 _nTerrainBlock = _pTerrainObject->GetCellBlock( _nCoordX, _nCoordY, _vTerrainBlock );
        for( int32 n = 0; n < _nTerrainBlock; n ++ ){
            _vTerrainBlockList.insert( _vTerrainBlock[n] );
        }

        color32 _nOldColor = _pTerrainObject->GetCellColor( _nCoordX, _nCoordY );
        _AddTerrainCellColorInfo( _nCoordX, _nCoordY, _nOldColor );
        _pTerrainObject->SetCellColor( _nCoordX, _nCoordY, cBrushColor );
    }

    set< CTerrainBlock* >::iterator it = _vTerrainBlockList.begin();
    set< CTerrainBlock* >::iterator it_end = _vTerrainBlockList.end();
    for (; it != it_end; it++) {
        CTerrainBlock* _pTerrainBlock = it.first();
        _pTerrainBlock->UpdateGeometry();
    }
    //m_rTerrainActiveBlockHelperObject->UpdateActiveBlock( _nCoordX, _nCoordY, nBrushSize, True );
}

void CTerrainColorOperator::_FinishedWork(){
    //CTerrainObject* _pTerrainObject = m_pSceneMgr->GetTerrainObject();
    //map< uint32, STerrainColorInfo >::iterator it = m_vTerrainCellHeightInfoList.begin();
    //map< uint32, STerrainColorInfo >::iterator it_end = m_vTerrainCellHeightInfoList.end();
    //for(; it != it_end; it++){
    //    uint32 _nKey = it.first();
    //    int32 _nX = HIWORD( _nKey );
    //    int32 _nY = LOWORD( _nKey );
    //    it.second().m_cNewColor = _pTerrainObject->GetCellColor( _nX, _nY );
    //}
    CTerrainColorCmd* _pTerrainHeightCmd = NEW CTerrainColorCmd( &m_vTerrainCellHeightInfoList );
    m_pSceneMgr->GetCommandMgr()->AddCommand( _pTerrainHeightCmd );
    m_vTerrainCellHeightInfoList.clear();
}
    


